package battleshipgame.ui;

import battleshipgame.logic.Board.SquareStatus;
import battleshipgame.logic.*;
import battleshipgame.logic.Player;
import battleshipgame.logic.Player.TypeHumanOrBot;
import battleshipgame.manager.*;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Scanner;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

/**
 *
 * @author dunay
 */
public class WebIOManager extends HttpServlet {

    public enum SessionState {

        GAME_STARTED,
        SELECT_INPUT_TYPE,
        MANUAL_INPUT_STATE,
        WAIT_FOR_ALL_USERS_TO_LOGIN,
        IN_GAME_WAIT_FOR_USER_INPUT,
        GAME_FINISHED,
        NONE
    };

    public static enum UserInputType {

        NONE,
        // INIT GAME
        XML_INPUT,
        MANUAL_INPUT,
        RESTART_GAME,
        ADD_PLAYER,
        ADD_BATTLESHIP,
        INIT_GAME_FINISHED,
        SELECT_PLAYER,
        SELECT_USER,
        //IN GAME
        SELECT_OPPONENT,
        MARK_SQUARE, CANCEL_MARK_SQUARE, BOMB_SQUARE, APPROVE_BOT_ATTACK, WITHDRAW
    };
    public static int MAX_INACTIVE_INTERVAL = 120;
    private GameManager gameManager;
    public PrintWriter out;
    public HttpServletRequest currentRequest;
    private UserInputType currentUserInput;
    private int opponentId;
    private int userId;
    private String coordinateSelected;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        //getServletContext().get
        if (getServletContext().getAttribute("gameManager") == null) {
            gameManager = new GameManager();
            getServletContext().setAttribute("gameManager", gameManager);
        } else {
            gameManager = (GameManager) getServletContext().getAttribute("gameManager");
        }
    }

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        out = response.getWriter();
        currentRequest = request;

        //print the start of the html file
        out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
        out.println("<html>");
        out.println("<head>");
        out.println("<link rel='stylesheet' type='text/css' href='click/click.css' />");
        out.println("</head>");
        out.println("<body>");
        out.println("<div id=\"time\"></div>");
        out.println("<h3 style=\"color:red\" id=errorMessage color=red></h3>");

        try {
            handleParameters();

            //Enters main game logic
            gameManager.setCurrentUserInput(currentUserInput);
            gameManager.playTheGame(this);
        } catch (InvalidInputException e) {
            printException(e);

        } catch (Exception e) {
            printException(e);
        } finally {
            //print the end of the html file
            out.println("</body>");
            out.println("</html>");
            out.close();
        }
    }

    //Handle Parameters
    private void handleParameters() {
        if (currentRequest.getContentType() != null
                && currentRequest.getContentType().toLowerCase().indexOf("multipart/form-data") > -1) {
            try {
                Collection<Part> parts = currentRequest.getParts();
                for (Part part : parts) {
                    part.write("samplefile");

                    StringBuilder fileContent = new StringBuilder();
                    fileContent.append(readFromInputStream(part.getInputStream()));


                    if (part.getName().equals("file1")) {
                        FileOutputStream f = new FileOutputStream(currentRequest.getRealPath("/") + "battleship.xml");
                        f.write(fileContent.toString().getBytes());
                        f.close();
                    } else if (part.getName().equals("userInputType")) {
                        currentUserInput = UserInputType.valueOf((fileContent.toString()));
                    }
                }

            } catch (Exception e) {
                int x = 0; //should never get here
            }

        } else {
            try {
                if (currentRequest.getParameter("userInputType") != null && !(currentRequest.getParameter("userInputType").equals(""))) {
                    currentUserInput = UserInputType.valueOf((currentRequest.getParameter("userInputType")));
                } else {
                    currentUserInput = UserInputType.NONE;
                }
                if (currentRequest.getParameter("opponentId") != null) {
                    opponentId = Integer.parseInt(currentRequest.getParameter("opponentId"));
                    if (gameManager.getUserPlayer().getCurrentOpponent() == null || gameManager.getUserPlayer().getCurrentOpponent().getId() != opponentId) {
                        gameManager.setOpponent(opponentId);
                    }

                }
                if (currentRequest.getParameter("coordinateSelected") != null) {
                    coordinateSelected = currentRequest.getParameter("coordinateSelected");
                    gameManager.setCoordinateSelected(coordinateSelected);
                }
                if (currentRequest.getParameter("playerNameToAdd") != null) {
                    String playerNameToAdd = currentRequest.getParameter("playerNameToAdd");
                    gameManager.setPlayerNameToAdd(playerNameToAdd);
                }
                if (currentRequest.getParameter("listOfBattleships") != null) {
                    String battleshipName = currentRequest.getParameter("listOfBattleships");
                    gameManager.setBattleshipNameToAdd(battleshipName);
                }

                if (currentRequest.getParameter("listOfPlayers") != null) {
                    int playerIndex = Integer.parseInt(currentRequest.getParameter("listOfPlayers"));
                    gameManager.setCurrentPlayer(playerIndex);
                }

                if (currentRequest.getParameter("Direction") != null) {
                    Player.Direction direction = Player.Direction.valueOf(currentRequest.getParameter("Direction"));
                    gameManager.setBattleshipDirectionToAdd(direction);
                }

                if (currentRequest.getParameter("playerType") != null) {
                    TypeHumanOrBot playerType = TypeHumanOrBot.valueOf(currentRequest.getParameter("playerType"));
                    gameManager.setPlayerType(playerType);
                }

                if (currentRequest.getParameter("userId") != null) {
                    userId = Integer.parseInt(currentRequest.getParameter("userId"));
                    gameManager.setUserPlayer(userId);
                    //if (gameManager.currentOpponent == null || gameManager.currentOpponent.getId() != opponentId) {
                    //   gameManager.setOpponent(opponentId);
                }
            } catch (Exception e) {
                StringWriter sw = new StringWriter();
                new Throwable("").printStackTrace(new PrintWriter(sw));
                String stackTrace = sw.toString();
                int x = 0; //should never get here
//            printException(e);
            }
        }
    }

    public void printException(Exception e) {
        StringWriter sw = new StringWriter();
        new Throwable("").printStackTrace(new PrintWriter(sw));
        String stackTrace = sw.toString();
        out.println("<script  type=\"text/javascript\"> "
                + "document.getElementById('errorMessage').innerHTML = '"
                + e.toString().replace("'", "")
                + "';");
        out.println("</script>");
    }

    public void printManualInit(Player currentPlayer) {
        out.println("<form name=\"mainForm\" enctype=\"application/x-www-form-urlencoded\\?\" metho=\"POST\">");

        out.println("<table border=2 name=\"mainTable\">");
        out.println("<input type=hidden name=userInputType>");
        out.println("<input type=hidden name=coordinateSelected>");
        out.println("<input type=hidden name=battleshipNameToAdd>");
        out.println("<input type=hidden name=battleshipDirection>");

        out.println("<tr>");
        out.println("<td>");
        printInitMenu();
        out.println("</td>");
        if (currentPlayer != null) {
            out.println("<td>");
            printCurrnetPlayerInit(currentPlayer);
            out.println("</td>");
        }

        out.print("<tr><td><input type=button name=finishEditing value='finish editing' onClick=\"javascript:document.mainForm.userInputType.value ='INIT_GAME_FINISHED'; document.mainForm.submit()\"");
        if (gameManager.initGameFinished()) {
            out.println(">");
        } else {
            out.println(" disabled=\"disabled\">");
        }
        out.println("</td></tr>");
        out.println("</table>");
        out.println("</form>");
    }

    private void printInitMenu() {
        out.println("<script type=\"text/javascript\">\n"
                + "function addPlayer() {\n"
                + "document.mainForm.userInputType.value='ADD_PLAYER';\n"
                + "document.mainForm.submit();"
                + "}\n</script>");

        out.println("<table><tr>");
        out.println("<td>new Player Name:</td>");
        out.println("<td><input type=text name=playerNameToAdd></td>");
        out.println("<td><select name=playerType>");
        out.println("<option value=HUMAN>HUMAN</option>");
        out.println("<option value=BOT>BOT</option>");
        out.println("</select></td>");
        out.println("</tr>");
        out.println("<tr>");
        out.print("<td><input type=button value='Add Player' onClick=addPlayer()");
        if (gameManager.players.size() == Constants.MAX_NUM_OF_PLAYERS) {
            out.println(" disabled=\"disabled\" ></td>");
        } else {
            out.println("></td>");
        }

        out.println("</tr>");
        out.println("<tr>");
        out.println("<td>List of Players:</td></tr>");
        out.println("<script type=\"text/javascript\">\n"
                + "function selectPlayerToEdit() {\n"
                + "document.mainForm.userInputType.value='SELECT_PLAYER';\n"
                + "document.mainForm.submit();"
                + "}\n</script>");
        out.println("<tr><td><select onClick=selectPlayerToEdit() name=listOfPlayers size=" + Constants.MAX_NUM_OF_PLAYERS + ">");
        for (int i = 0; i < gameManager.players.size(); i++) {
            out.println("<option value=" + gameManager.players.get(i).getId() + ">" + gameManager.players.get(i).getName() + "</option>");
        }
        out.println("</select>");
        out.println("</td></tr></table>");
    }

    //prints info for player to init
    private void printCurrnetPlayerInit(Player currentPlayer) {

        out.println("<table>");
        out.println("<tr>");
        out.println("<td colspan=2><h1>Current Player is " + currentPlayer.getName() + "</h1></td>");
        out.println("</tr>");

        out.println("<tr>");
        out.println("<td>");
        try {
            if (currentPlayer != null) {
                printBoard(currentPlayer.getName(),
                        currentPlayer.getBoard(),
                        null, true);
            }
        } catch (InvalidInputException e) {
            printException(e);

        } catch (Exception e) {
            printException(e);
        }
        out.println("</td>");
        out.println("<td>");
        out.println("<table><tr><td>");
        out.println("<select name=listOfBattleships size=5>");

        boolean firstbattleShipMarked = false;
        for (int i = 0; i < Constants.battleShipNamesList.length; i++) {
            out.print("<option name='" + Constants.battleShipNamesList[i] + "'");
            if (gameManager.currentPlayer.hasBattleship(Constants.battleShipNamesList[i]) == false) {
                if (firstbattleShipMarked == false) {
                    out.print(" selected=\"selected\" ");
                    firstbattleShipMarked = true;
                }
                out.println(">");
            } else {
                // battleship exist do not allow to add it again
                out.println("disabled=\"disabled\">");
            }
            out.println(Constants.battleShipNamesList[i] + "</option>");
        }
        out.println("</td></tr>");
        out.println("<tr><td>");
        out.println("<select name='Direction'><option value='HORIZONTAL'>HORIZONTAL</option><option value='VERTICAL'>VERTICAL</option></select>");
        out.println("</td></tr>");
        out.println("</table>");

        out.println("</table>");
    }

    private String readFromInputStream(InputStream inputStream) {
        return new Scanner(inputStream).useDelimiter("\\Z").next();
    }

    public void printGame(Player currentPlayer, Player userPlayer) throws InvalidInputException {
        out.println("<script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-1.4.4.js\"></script>");

        out.println("<script type=\"text/javascript\" src=Clock.js></script>");
        if (userPlayer != currentPlayer) {
            out.println("<script type=\"text/javascript\" src=CheckCurrentPlayer.js></script>");
        }
        out.println("<form name=\"mainForm\" enctype=\"application/x-www-form-urlencoded\\?\" metho=\"POST\">");
        out.println("<table border=2 name=\"mainTable\">");

        out.println("<input type=hidden name=userPlayer value=\"" + userPlayer.getName() + "\">");
        out.println("<input type=hidden name=currentPlayer value=\"" + gameManager.currentPlayer.getName() + "\">");
        out.println("<input type=hidden name=userInputType>");
        out.println("<input type=hidden name=coordinateSelected>");
        if (userPlayer != currentPlayer) {
            out.println("<tr><td colspan=3><h1>Hello " + userPlayer.getName() + ". Current Player is " + currentPlayer.getName() + "</h1></td></tr>");
        } else {
            out.println("<tr><td colspan=3><h1>Hello " + userPlayer.getName() + ". it's your turn</h1></td></tr>");
            currentRequest.getSession().setMaxInactiveInterval(MAX_INACTIVE_INTERVAL);
        }
        

        out.println("<tr><td>");
        printMenu(currentPlayer, userPlayer);
        // close of innter options tables
        out.println("</td>");
        if (gameManager.getUserPlayer().getCurrentOpponent() != null) {
            printBoard(gameManager.getUserPlayer().getCurrentOpponent().getName(),
                    gameManager.getUserPlayer().getCurrentOpponent().getBoard(),
                    currentPlayer.getMarkBoard(gameManager.getUserPlayer().getCurrentOpponent().getName()), false);

            out.println("<td>");
            printOpponentInfo();
            //out.println("</td>");
            out.println("</tr>");
        }
        out.println("</table>");
        out.println("</form>");

    }

    private void printOpponentInfo() {

        out.println("<table><tr><td colspan=2>Opponent info:</td></tr>");
        out.println("<tr><td>Name</td><td>" + gameManager.getUserPlayer().getCurrentOpponent().getName() + "</td></tr>");
        out.println("<tr><td>Type</td><td>" + gameManager.getUserPlayer().getCurrentOpponent().getHumanOrBot().toString() + "</td></tr>");
        out.println("<tr><td>Remaining ships</td><td>" + gameManager.getUserPlayer().getCurrentOpponent().getRemainingBattleships() + "</td></tr>");
        out.println("</table>");
    }

    private void printMenu(Player currentPlayer, Player userPlayer) {
        out.println("<table><tr><td>");
        out.println("Select Opponent:");
        out.println("<select name=opponentId onChange=\"javascript: document.mainForm.userInputType.value='SELECT_OPPONENT'; document.mainForm.submit()\"> ");
        out.println("<option  value=-1> </option>");
        for (int i = 0; i < gameManager.players.size(); i++) {
            if (!(gameManager.players.get(i).equals(userPlayer))) {
                out.print("<option  value=" + gameManager.players.get(i).getId());
                if (gameManager.getUserPlayer().getCurrentOpponent() != null && gameManager.getUserPlayer().getCurrentOpponent().getId() == i) {
                    out.print(" SELECTED ");
                }

                if (gameManager.players.get(i).IsPlayerDead()) {
                    out.print(" disabled=\"disabled\"");
                }

                out.print(">" + gameManager.players.get(i).getName() + "</option>");
            }
        }
        out.println("</select></td></tr>"
                + "<tr><td>Select Command:");

        if (userPlayer == currentPlayer) {
            out.println("<input type=\"radio\" name=\"commandSelected\" value=\"BOMB_SQUARE\"  checked>Bomb<br/>");
            out.println("<input type=\"radio\" name=\"commandSelected\" value=\"MARK_SQUARE\" >Mark<br/>");
        } else {
            out.println("<input type=\"radio\" name=\"commandSelected\" value=\"BOMB_SQUARE\"  disabled>Bomb<br/>");
            out.println("<input type=\"radio\" name=\"commandSelected\" value=\"MARK_SQUARE\"  checked>Mark<br/>");
        }

        out.println("<input type=\"radio\" name=\"commandSelected\" value=\"CANCEL_MARK_SQUARE\" >Cancel Mark<br/>");
        out.println("<input type=\"button\" name=\"withdraw\" value=\"WITHDRAW\" onclick=\"javascript: document.mainForm.userInputType.value='WITHDRAW';mainForm.submit()\"><br/>");
        out.println("</td></tr></table>");
    }

    private void printBoard(String playerName, Board board, MarkMatrix markmatrix, boolean showBattleShips) throws InvalidInputException {

        out.println("<script type=\"text/javascript\">\n"
                + "function buttonClicked(coordinate) {");
        if (gameManager.currentState == SessionState.IN_GAME_WAIT_FOR_USER_INPUT) {
            out.println("for (i=0;i<document.mainForm.commandSelected.length;i++){\n"
                    + "if (document.mainForm.commandSelected[i].checked==true)\n"
                    + "selectedIndex=i; \n"
                    + "}\n "
                    + "document.mainForm.userInputType.value = document.mainForm.commandSelected[selectedIndex].value;\n");
        } else {
            if (gameManager.currentPlayer.getTotalBattleship() == Constants.NUM_BATTLESHIPS) {
                out.println("return;");
            }
            out.println("document.mainForm.userInputType.value = 'ADD_BATTLESHIP';");
        }
        out.println(
                "document.mainForm.coordinateSelected.value = coordinate;\n"
                + "document.mainForm.submit();\n"
                + "}\n</script>");

        out.println("<td>");
        out.println("Board of: " + playerName);
        out.println("<table name=opponentBoard width=300 height=100 border=1>");

        out.println("<tr>");
        out.println("<td></td>");
        for (char i = 'A'; i <= 'J'; i++) {
            out.println("<td>" + i + "</td>");
        }
        out.println("</tr>");

        for (char j = '1'; j <= '9' + 1; j++) {
            out.println("<tr>");
            if (j != '9' + 1) {
                out.println("<td>" + j + "</td>");
            } else {
                out.println("<td>10</td>");
            }

            for (char i = 'A'; i <= 'J'; i++) {
                String coordinate;
                if (j != '9' + 1) {
                    coordinate = i + "" + j;
                } else {
                    coordinate = i + "10";
                }
                String buttonValue = getButtonValueToPrint(board, markmatrix, coordinate, showBattleShips);

                out.println("<td class=\"" + buttonValue + "\"><input type=button name=" + coordinate + " value=\"" + buttonValue + "\" onClick=\"javascript:buttonClicked('" + coordinate + "')\"></td>");
            }
            out.println("</tr>");
        }

        out.println("</table>");
        out.println("</td>");
    }

    /*
    public static UserInputType getCommandFromUser() {
    throw new UnsupportedOperationException("Not yet implemented");
    }
     */
    /*
    public String getCoordianteFromUser() {
    throw new UnsupportedOperationException("Not yet implemented");
    }*/
    private String getButtonValueToPrint(Board board, MarkMatrix markmatrix, String coordiante, boolean showBattleShip) throws InvalidInputException {
        SquareStatus squareStatus = board.getSquareStatusByCoordinate(coordiante);
        //TODO delte debug

        char charToPrint = ' ';
        if (showBattleShip) {
            Battleship battleship = board.getSquareByCoordinate(coordiante).getMyBattleship();
            if (battleship != null) {
                charToPrint = battleship.getName().charAt(0);
            } else {
                charToPrint = 'S';
            }
        } else {
            switch (squareStatus) {
                case BOMBED_SEA:
                    charToPrint = 'O';
                    break;
                case BOMBED_BATTLESHIP:
                    charToPrint = 'X';
                    break;
                case SEA:
                case BATTLESHIP:
                    if (markmatrix.IsMarked(coordiante)) {
                        charToPrint = 'M';
                    } else {
                        charToPrint = 'S';
                    }
                    break;
            }
        }
        return charToPrint + "";
    }

    public void showWelcomeScreen() {
        out.println("<h1>init page</h1>");
        out.println("<form name=\"boardInputForm\" enctype=\"multipart/form-data\" method=\"POST\">");
        out.println("select board input type:<br>");
        out.println("<input type=\"radio\" name=\"userInputType\" value=\"XML_INPUT\" onClick=\"javascript:document.boardInputForm.file1.disabled=false\">xml &nbsp; &nbsp; &nbsp; ");
        out.println("<input type=\"file\" name=\"file1\" ><br>");

        out.println("<input type=\"radio\" name=\"userInputType\" value=\"MANUAL_INPUT\" onClick=\"javascript:document.boardInputForm.file1.disabled=true\">manual<br/>");
        out.println("<input type=\"submit\" name=\"submilt\" value=\"submit\" ><br/>");
        out.println("</form>");

        //throw new UnsupportedOperationException("Not yet implemented");
    }

    public void AlertAlreadyBombed() {
        out.println("<script type=\"text/javascript\"> alert('Already Bombed'); </script>");
    }

    public void declareWinner(String playerName) {

        out.println("<h1>" + playerName + " has won the game!!!!</h1><br/>");
        out.println("<form name=\"mainForm\" enctype=\"application/x-www-form-urlencoded\\?\" metho=\"POST\">");
        out.println("<input type=hidden name=userInputType value='RESTART_GAME'>");
        out.println("<input type=submit value='Restart Game'>");
        out.println("</form>");
    }

    public void printWaitGameScreen(String userPlayerName) {
        out.println("<script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-1.4.4.js\"></script>");
        out.println("<script type=\"text/javascript\" src=CheckAllUsersConnected.js></script>");
        out.println(userPlayerName + ", please wait for all players to login...");
        out.println("<br><a href=WebIOManager> check game</a>");
    }

    public void showErrorPage() {
        out.println("<h1>game started, no more available players</h1>");
    }

    public void handeUserLogin() {
        out.println("<form name=\"mainForm\" enctype=\"application/x-www-form-urlencoded\\?\" metho=\"POST\">");
        out.println("<input type=hidden name=userInputType>");
        out.println("enter your name:");
        out.println("<select name=userId onChange=\"javascript: document.mainForm.userInputType.value='SELECT_USER'; document.mainForm.submit()\"> ");
        out.println("<option  value=-1> </option>");
        for (int i = 0; i < gameManager.players.size(); i++) {
            if (gameManager.players.get(i).getHumanOrBot() == Player.TypeHumanOrBot.HUMAN && !(gameManager.players.get(i).isConnected())) {
                out.print("<option  value=" + gameManager.players.get(i).getId());
                out.print(">" + gameManager.players.get(i).getName() + "</option>");
            }
        }
        out.println("</select>");
        out.println("</form>");


    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
